﻿#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;
#include <functional>
#include<memory>

//实现shared_ptr'
//底层是引用计数

namespace xxl
{
	template<class T>
	class shared_ptr
	{
	public:
		explicit shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			,_pcount(new int(1))
		{ }

		//实现定制删除器
		template <class D>
		shared_ptr(T* ptr, D del)
			:_ptr(ptr)
			,_pcount(new int(1))
			,_del(del)
		{ }

		//拷贝构造
		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
		{
			++(*_pcount);
		}

		void release()
		{
			if (--(*_pcount) == 0)
			{
				//delete _ptr;
				_del(_ptr);
				delete _pcount;
			}
		}

		//拷贝赋值
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				release();

				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}

			return *this;
		}

		~shared_ptr()
		{
			release();
		}

		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		int use_count() const
		{
			return *_pcount;
		}

		T* get() const
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _pcount;

		//定制删除器不需要有返回值 参数为T*
		//当function没有绑定对象 默认初始化 调用时会抛出异常 因此这里需要给个默认的初始值
		function<void(T*)> _del = [](T* ptr) {delete ptr; };
		/*function<void(T*)> _del;*/
	};

	/*
	weak_ptr不⽀持RAII，也不⽀持访问资源
	绑定到shared_ptr时，不增加shared_ptr的引⽤计数，因此用来解决循环引用问题
	*/

	/*
	weak_ptr也没有重载operator*和operator->等，因为他不参与资源管理，那么如果他绑定的shared_ptr已经释放了资源，那么他去访问资源就是很危险的
	weak_ptr⽀持expired检查指向的资源是否过期，use_count也可获取shared_ptr的引⽤计数，
	weak_ptr想访问资源时，可以调⽤lock返回⼀个管理资源的shared_ptr，
	如果资源已经被释放，返回的shared_ptr是⼀个空对象，如果资源没有释放，则通过返回的shared_ptr访问资源是安全的。
	*/
	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr()
		{
		}

		weak_ptr(const shared_ptr<T>& sp)
			:_ptr(sp.get())
		{
		}

		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}
	private:
		T* _ptr = nullptr;
	};
}

struct Date
{
	int _year;
	int _month;
	int _day;

	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}

	~Date()
	{
		cout << "~Date()" << endl;
	}
};


//int main()
//{
//	xxl::shared_ptr<Date> sp1(new Date);
//	xxl::shared_ptr<Date> sp2(sp1);
//
//	xxl::shared_ptr<Date> sp3(new Date);
//
//	sp1 = sp1;
//	sp1 = sp2;
//
//	sp1 = sp3;
//	sp2 = sp3;
//
//	return 0;
//}
//


template<class T>
void DeleteArrayFunc(T* ptr)
{
	delete[] ptr;
}

template<class T>
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};

class Fclose
{
public:
	void operator()(FILE* ptr)
	{
		cout << "fclose:" << ptr << endl;
		fclose(ptr);
	}
};

//int main()
//{
//
//	// 定制删除器  函数指针/仿函数/lambda
//	xxl::shared_ptr<Date> sp1(new Date[5], DeleteArray<Date>());
//	xxl::shared_ptr<Date> sp2(new Date[5], DeleteArrayFunc<Date>);
//
//	auto delArrOBJ = [](Date* ptr) {delete[] ptr; };
//	xxl::shared_ptr<Date> sp3(new Date[5], delArrOBJ);
//
//	xxl::shared_ptr<FILE> sp4(fopen("Test.cpp", "r"), Fclose());
//	xxl::shared_ptr<FILE> sp5(fopen("Test.cpp", "r"), [](FILE* ptr) {
//		cout << "fclose:" << ptr << endl;
//		fclose(ptr);
//		});
//
//	xxl::shared_ptr<Date> sp6(new Date);
//
//
//	return 0;
//}

//int main()
//{
//	shared_ptr<Date> sp1(new Date(2024, 9, 11));
//	shared_ptr<Date> sp2 = make_shared<Date>(2024, 9, 11); //make_shared底层是可变参数 同时有内存池防止碎片化 会更高效一点
//
//	//类型转换运算符重载 指向有效对象返回true 指向空或被释放 返回false
//	if (sp1.operator bool())
//	//if (sp1)
//		cout << "sp1 is not nullptr" << endl;
//	shared_ptr<Date> sp3;
//	if (!sp3)
//		cout << "sp3 is nullptr" << endl;
//
//
//	// 报错  直接赋值类型不匹配 走构造函数
//	//shared_ptr<Date> sp5 = new Date(2024, 9, 11);
//	//unique_ptr<Date> sp6 = new Date(2024, 9, 11);
//	return 0;
//}



//循环引用的场景

struct ListNode
{
	int _data = 0;
	//使用这两个类型会不匹配
	/*ListNode* _next;
	ListNode* _prev;*/

	//使用这两个会造成循环引用
	//xxl::shared_ptr<ListNode> _next;
	//xxl::shared_ptr<ListNode> _prev;

	// 这里改成weak_ptr，当n1->_next = n2;绑定shared_ptr时
	// 不增加n2的引用计数，不参与资源释放的管理，就不会形成循环引用了
	xxl::weak_ptr<ListNode> _next;
	xxl::weak_ptr<ListNode> _prev;

	~ListNode()
	{
		cout << "~ListNode()" << endl;
	}
};

/*
如下图所述场景，n1和n2析构后，管理两个节点的引⽤计数减到1
1. 右边的节点什么时候释放呢，左边节点中的_next管着呢，_next析构后，右边的节点就释放了。
2. _next什么时候析构呢，_next是左边节点的的成员，左边节点释放，_next就析构了。
3. 左边节点什么时候释放呢，左边节点由右边节点中的_prev管着呢，_prev析构后，左边的节点就释
放了。
4. _prev什么时候析构呢，_prev是右边节点的成员，右边节点释放，_prev就析构了。
• ⾄此逻辑上成功形成回旋镖似的循环引⽤，谁都不会释放就形成了循环引⽤，导致内存泄漏
*/


//int main()
//{
//	// 循环引用 -- 内存泄露
//	xxl::shared_ptr<ListNode> n1(new ListNode);
//	xxl::shared_ptr<ListNode> n2(new ListNode);
//	cout << n1.use_count() << endl;
//	cout << n2.use_count() << endl;
//	n1->_next = n2;
//	n2->_prev = n1;
//	cout << n1.use_count() << endl;
//	cout << n2.use_count() << endl;
//
//	// weak_ptr不支持管理资源，不支持RAII
//	// weak_ptr是专门绑定shared_ptr，不增加他的引用计数，作为一些场景的辅助管理
//	/*std::weak_ptr<ListNode> wp(new ListNode);*/
//
//	return 0;
//}


int main()
{
	std::shared_ptr<string> sp1(new string("111111"));
	std::shared_ptr<string> sp2(sp1);

	std::weak_ptr<string> wp = sp1;

	cout << wp.expired() << endl;  //expired判断指向的资源是否过期
	cout << wp.use_count() << endl;

	// sp1和sp2都指向了其他资源，则weak_ptr就过期了
	sp1 = make_shared<string>("222222");
	cout << wp.expired() << endl;
	cout << wp.use_count() << endl;

	sp2 = make_shared<string>("333333");
	cout << wp.expired() << endl;
	cout << wp.use_count() << endl;


	wp = sp1;
	/*
	weak_ptr本身不参与资源管理，不会增加引用计数
	但通过lock()方法可以获取一个shared_ptr对象，这个新获取的shared_ptr会正常增加引用计数
	*/
	//std::shared_ptr<string> sp3 = wp.lock();
	auto sp3 = wp.lock();
	cout << wp.expired() << endl;
	cout << wp.use_count() << endl;

	*sp3 += "###";
	cout << *sp1 << endl;  //sp1也改变 此时sp3也参与管理

	sp1 = sp2;

	return 0;
}